"""
张币转换模块
由币转换为张，或者张转换为币
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class UnitConvertManager:
    """张币转换管理器"""
    
    # 限速配置：10次/2s
    RATE_LIMIT_REQUESTS = 10
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化张币转换管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        logger.info(f"张币转换管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：10次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def convert_contract_coin(self, inst_id: str, px: str, 
                             sz: Optional[str] = None,
                             unit: Optional[str] = None,
                             op_type: Optional[str] = None) -> Dict:
        """
        张币转换
        
        Args:
            inst_id: 产品ID，如 BTC-USD-SWAP
            px: 委托价格
                - 期权必填
                - 期货、永续必填
                - 币币杠杆可不填
            sz: 数量，币或张
                - 币转张时，填写币的数量
                - 张转币时，填写张的数量
            unit: 币或张
                - coin: 币转张
                - usds: 张转币
                - 不填时，默认币转张
            op_type: 操作类型
                - open: 开仓
                - close: 平仓
                - 不填时，默认open
            
        Returns:
            转换结果字典，包含以下字段：
            - instId: 产品ID
            - px: 委托价格
            - sz: 转换后的数量
            - unit: 转换后的单位
            - type: 产品类型
        """
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            # 构建请求参数
            params = {
                "instId": inst_id,
                "px": px
            }
            if sz:
                params["sz"] = sz
            if unit:
                params["unit"] = unit
            if op_type:
                params["opType"] = op_type
            
            logger.info(f"张币转换: {params}")
            result = self.public_api.get_convert_contract_coin(**params)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"张币转换失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            if not data_list:
                logger.warning("未获取到转换结果")
                return {}
            
            convert_data = data_list[0]
            logger.info(f"张币转换成功: {convert_data}")
            
            return convert_data
            
        except Exception as e:
            logger.error(f"张币转换异常: {e}")
            raise
    
    def coin_to_contract(self, inst_id: str, px: str, coin_amount: float,
                        op_type: str = "open") -> Dict:
        """
        币转张（计算需要多少张合约）
        
        Args:
            inst_id: 产品ID
            px: 委托价格
            coin_amount: 币的数量
            op_type: 操作类型 (open/close)
            
        Returns:
            转换结果，包含张数
        """
        result = self.convert_contract_coin(
            inst_id=inst_id,
            px=px,
            sz=str(coin_amount),
            unit="coin",
            op_type=op_type
        )
        
        if result:
            return {
                "inst_id": inst_id,
                "price": float(px),
                "coin_amount": coin_amount,
                "contract_amount": float(result.get("sz", 0)),
                "unit": result.get("unit"),
            }
        
        raise ValueError("转换失败")
    
    def contract_to_coin(self, inst_id: str, px: str, contract_amount: float,
                        op_type: str = "open") -> Dict:
        """
        张转币（计算张合约对应多少币）
        
        Args:
            inst_id: 产品ID
            px: 委托价格
            contract_amount: 张的数量
            op_type: 操作类型 (open/close)
            
        Returns:
            转换结果，包含币数
        """
        result = self.convert_contract_coin(
            inst_id=inst_id,
            px=px,
            sz=str(contract_amount),
            unit="usds",
            op_type=op_type
        )
        
        if result:
            return {
                "inst_id": inst_id,
                "price": float(px),
                "contract_amount": contract_amount,
                "coin_amount": float(result.get("sz", 0)),
                "unit": result.get("unit"),
            }
        
        raise ValueError("转换失败")
    
    def calculate_position_value(self, inst_id: str, px: str, 
                                 contract_amount: float) -> Dict:
        """
        计算持仓价值（张转币）
        
        Args:
            inst_id: 产品ID
            px: 当前价格
            contract_amount: 持仓张数
            
        Returns:
            持仓价值信息
        """
        result = self.contract_to_coin(inst_id, px, contract_amount)
        
        return {
            "inst_id": inst_id,
            "contract_amount": contract_amount,
            "price": float(px),
            "position_value": result["coin_amount"],
            "position_value_usd": result["coin_amount"] * float(px),
        }
    
    def calculate_order_size(self, inst_id: str, px: str, 
                            target_value: float) -> Dict:
        """
        根据目标价值计算下单张数（币转张）
        
        Args:
            inst_id: 产品ID
            px: 委托价格
            target_value: 目标价值（币）
            
        Returns:
            下单张数信息
        """
        result = self.coin_to_contract(inst_id, px, target_value)
        
        return {
            "inst_id": inst_id,
            "target_value": target_value,
            "price": float(px),
            "order_size": result["contract_amount"],
            "actual_value": result["coin_amount"],
        }
    
    def batch_convert(self, conversions: List[Dict]) -> List[Dict]:
        """
        批量转换
        
        Args:
            conversions: 转换列表，每个元素包含 inst_id, px, sz, unit, op_type
            
        Returns:
            转换结果列表
        """
        results = []
        
        for conv in conversions:
            try:
                result = self.convert_contract_coin(**conv)
                results.append({
                    "success": True,
                    "input": conv,
                    "output": result
                })
            except Exception as e:
                logger.error(f"转换失败: {conv}, {e}")
                results.append({
                    "success": False,
                    "input": conv,
                    "error": str(e)
                })
        
        return results


# 便捷函数
def convert_contract_coin(inst_id: str, px: str, sandbox: bool = True, **kwargs) -> Dict:
    """
    便捷函数：张币转换
    
    Args:
        inst_id: 产品ID
        px: 委托价格
        sandbox: 是否使用模拟盘
        **kwargs: 其他参数传递给convert_contract_coin
        
    Returns:
        转换结果字典
    """
    manager = UnitConvertManager(sandbox=sandbox)
    return manager.convert_contract_coin(inst_id, px, **kwargs)


def coin_to_contract(inst_id: str, px: str, coin_amount: float, 
                    sandbox: bool = True) -> Dict:
    """
    便捷函数：币转张
    
    Args:
        inst_id: 产品ID
        px: 委托价格
        coin_amount: 币的数量
        sandbox: 是否使用模拟盘
        
    Returns:
        转换结果
    """
    manager = UnitConvertManager(sandbox=sandbox)
    return manager.coin_to_contract(inst_id, px, coin_amount)


def contract_to_coin(inst_id: str, px: str, contract_amount: float,
                    sandbox: bool = True) -> Dict:
    """
    便捷函数：张转币
    
    Args:
        inst_id: 产品ID
        px: 委托价格
        contract_amount: 张的数量
        sandbox: 是否使用模拟盘
        
    Returns:
        转换结果
    """
    manager = UnitConvertManager(sandbox=sandbox)
    return manager.contract_to_coin(inst_id, px, contract_amount)


def calculate_position_value(inst_id: str, px: str, contract_amount: float,
                            sandbox: bool = True) -> Dict:
    """
    便捷函数：计算持仓价值
    
    Args:
        inst_id: 产品ID
        px: 当前价格
        contract_amount: 持仓张数
        sandbox: 是否使用模拟盘
        
    Returns:
        持仓价值信息
    """
    manager = UnitConvertManager(sandbox=sandbox)
    return manager.calculate_position_value(inst_id, px, contract_amount)


def calculate_order_size(inst_id: str, px: str, target_value: float,
                        sandbox: bool = True) -> Dict:
    """
    便捷函数：根据目标价值计算下单张数
    
    Args:
        inst_id: 产品ID
        px: 委托价格
        target_value: 目标价值（币）
        sandbox: 是否使用模拟盘
        
    Returns:
        下单张数信息
    """
    manager = UnitConvertManager(sandbox=sandbox)
    return manager.calculate_order_size(inst_id, px, target_value)
